﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using PInitiatives.Models;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Text;

namespace PInitiatives.Helpers
{
    public static class Html
    {
        private static string _baseUrl;
        private static HtmlHelper _htmlHelper;

        public static IHtmlString CategorySiteMap(this HtmlHelper html, int id)
        {
            _htmlHelper = html;
            StringBuilder siteMap = new StringBuilder();
            PInitiativesEntities db = new PInitiativesEntities();
            Category category = db.Categories.SingleOrDefault(c => c.ID == id);

            if (category != null && category.ParentCategory != null)
            {
                siteMap.Append("<ul class=\"breadcrumb\">");
                siteMap.Append("Kategoria: ");
                BildParent(category.ParentCategory, siteMap);
                siteMap.Append("<li>" + category.Name + "</li>");

                siteMap.Append("</ul>");
            }
            return html.Raw(siteMap.ToString());
        }

        private static void BildParent(Category category, StringBuilder sb)
        {
            if (category.Parent != null)
            {
                BildParent(category.ParentCategory, sb);
                sb.Append("<li>");
                //sb.Append("<a href=\"" + _baseUrl + "/Initiative/Browse?category=" + category.ID + "\">");
                //sb.Append(category.Name);
                //sb.Append("</a>");
                sb.Append(LinkExtensions.ActionLink(_htmlHelper, category.Name, "Browse", "Initiative", new { category = category.ID }, "").ToHtmlString());
                sb.Append("<span class=\"divider\">></span>");
                sb.Append("</li>");
                //return null;
            }
        }
        
        public static IHtmlString CategoryTreeView(this System.Web.Mvc.HtmlHelper html, HttpRequestBase request )
        {
            PInitiativesEntities db = new PInitiativesEntities();
            IQueryable<Category> categories;
            string tmp = request.QueryString["category"];

            if (!string.IsNullOrEmpty(tmp))
            {
                int categoryID;
                int.TryParse(tmp, out categoryID);
                Category parentCategory = db.Categories.SingleOrDefault(c=>c.ID == categoryID);
                categories = db.Categories.Where(c => c.Left >= parentCategory.Left && c.Right <= parentCategory.Right).OrderBy(c=> c.Left);
            }
            else
               categories  = db.Categories.OrderBy(c => c.Left);
            
            StringBuilder treeView = new StringBuilder();

            int countTags = 0;

            List<int> level = new List<int>();
            bool rootTag = true;

            treeView.Append("<ul>");
            foreach (Category category in categories)
            {
                string name = category.Name;
                
                if (level.Count > 0)
                {
                    countTags = 0;
                    while (level[level.Count - 1] < category.Right)
                    {
                        countTags++;
                        level.RemoveAt(level.Count - 1);
                    }
                }


                AddClosingTags(treeView, countTags - 1);

                if (level.Count <= 2)
                {
                        
                    if (category.Right != category.Left + 1 && level.Count != 2)
                    {
                        if (!rootTag)
                        {
                            treeView.Append("<li>");
                            treeView.Append(LinkExtensions.ActionLink(html, category.Name, "Browse", "Initiative", new { category = category.ID }, "").ToHtmlString());
                            //treeView.Append(category.Name);
                            treeView.Append("<ul>");
                            //countTags++;
                        }
                        else
                            rootTag = false;

                        //Sprawdzac i zapisaywać ile gałąź ma potomków, 
                    }
                    else
                    {
                        treeView.Append("<li>");
                        treeView.Append(LinkExtensions.ActionLink(html, category.Name, "Browse", "Initiative", new { category = category.ID }, "").ToHtmlString());
                        treeView.Append("</li>");
                    }

                    level.Add(category.Right);
                }

            }
            AddClosingTags(treeView, countTags - 1);
            treeView.Append("</ul>");

            return html.Raw(treeView.ToString());
        }
        
        
        //public static IHtmlString CategoryTreeView2(this System.Web.Mvc.HtmlHelper html)
        //{
        //    PInitiativesEntities db = new PInitiativesEntities();
        //    var categories = db.Categories.OrderBy(c => c.Left);
        //    StringBuilder treeView = new StringBuilder();

        //    int countTags = 0;

        //    List<int> level = new List<int>();
        //    bool rootTag = true;

        //    treeView.Append("<ul>");
        //    foreach (Category category in categories)
        //    {
        //        if (level.Count > 0)
        //        {
        //            countTags = 0;
        //            while (level[level.Count - 1] < category.Right)
        //            {
        //                if (level.Count < 3)
        //                    countTags++;
        //                level.RemoveAt(level.Count - 1);
        //            }
        //        }

        //        AddClosingTags(treeView, countTags-1);

        //        if (level.Count < 2)
        //        {
        //            if (category.Right != category.Left + 1)
        //            {
        //                if (!rootTag)
        //                {
        //                    treeView.Append("<li id=" + "/Initiative/Browse?category=" + category.ID + ">");
        //                    treeView.Append("<a>" + category.Name + "</a>");
        //                    //treeView.Append(LinkExtensions.ActionLink(html, category.Name, "Browse", "Initiative", new { category = category.ID }, "").ToHtmlString());
        //                    //treeView.Append(category.Name);
        //                    treeView.Append("<ul>");
        //                }
        //                else
        //                    rootTag = false;

        //                //Sprawdzac i zapisaywać ile gałąź ma potomków, 
        //            }
        //            else
        //            {
        //                treeView.Append("<li id=" + "/Initiative/Browse?category=" + category.ID + ">");
        //                //treeView.Append(LinkExtensions.ActionLink(html, category.Name, "Browse", "Initiative", new { category = category.ID }, "").ToHtmlString());
        //                treeView.Append("<a>" + category.Name + "</a>");
        //                treeView.Append("</li>");
        //            }
        //        }

        //        level.Add(category.Right);
        //    }
        //    AddClosingTags(treeView, level.Count - 1);
        //    treeView.Append("</ul>");
            
        //    return html.Raw(treeView.ToString());
        //}

        private static StringBuilder AddClosingTags(StringBuilder sb, int n)
        {
            for (int i = 0; i < n; i++)
                sb.Append("</ul></li>");
            return sb;
        }
    }
    
    public class CategoryDDLItem
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public CategoryDDLItem(int id, string name) 
        {
            this.ID = id;
            this.Name = name;
        }
    }
    
    public static class CategoryManager
    {
        public static List<CategoryDDLItem> GetCategoryDDL()
        {
            PInitiativesEntities db = new PInitiativesEntities();
            List<CategoryDDLItem> ddl = new List<CategoryDDLItem>();
            string prefix = "";
            //Category root = db.Categories.SingleOrDefault(c => c.Parent == null);
            //ddl.Add(new CategoryDDLItem(root.ID, root.Name));
            
            var categories = db.Categories.OrderBy(c => c.Left);

            List<int> level = new List<int>();
            foreach (Category category in categories)
            {
                if (level.Count > 0)
                {
                    while (level[level.Count - 1] < category.Right)
                        level.RemoveAt(level.Count - 1);
                }

                prefix = GetPrefix(level.Count);
                ddl.Add(new CategoryDDLItem(category.ID, prefix + category.Name));
                //string tree = prefix + category.Name + "\n";
                level.Add(category.Right);
            }
            
            return ddl;
        }

        private static string GetPrefix(int n)
        {
            return new String('-', n);
        }

        public static Category CreateNewCategory(string name, int? parent)
        {
            PInitiativesEntities db = new PInitiativesEntities();
            Category parentCategory = db.Categories.SingleOrDefault(c => c.ID == parent);
            Category newCategory = new Category(name, parent, parentCategory.Right, parentCategory.Right + 1);

            UpdateTreeAfterAdd(parentCategory.Left, parentCategory.Right);

            db.Categories.Add(newCategory);
            db.SaveChanges();

            return newCategory;
        }

        public static void DeleteCategory(int id)
        {
            //PInitiativesEntities db = new PInitiativesEntities();
            //Category categoryToDel = db.Categories.Find(id);
            //db.Categories.Remove(categoryToDel);
            //db.SaveChanges();
            //UpdateTreeAfterDelete(categoryToDel.Left, categoryToDel.Right);
            PInitiativesEntities db = new PInitiativesEntities();
            Category category = db.Categories.Find(id);
            var categoriesToDel = db.Categories.Where(c => c.Left >= category.Left && c.Right <= category.Right).OrderByDescending(c=>c.Left);
            foreach (Category c in categoriesToDel)
                DeleteSingleCategory(c.ID);
            //ToDo: What about initiatives in deleting category ?

        }

        private static void DeleteSingleCategory(int id)
        {
            PInitiativesEntities db = new PInitiativesEntities();
            Category categoryToDel = db.Categories.Find(id);
            db.Categories.Remove(categoryToDel);
            db.SaveChanges();
            UpdateTreeAfterDelete(categoryToDel.Left, categoryToDel.Right);
        }

        public static void EditCategory(int id, string name, int? parent)
        {
            PInitiativesEntities db = new PInitiativesEntities();
            Category categoryToEdit = db.Categories.Find(id);
            categoryToEdit.Name = name;

            //ToDo: A better soulution ?? 
            if (categoryToEdit.Parent != parent)
            {
                categoryToEdit.Parent = parent;

                int tmpLeft = categoryToEdit.Left;
                int tmpRight = categoryToEdit.Right;
                categoryToEdit.Left = 0;
                categoryToEdit.Right = 0;
                UpdateTreeAfterDelete(tmpLeft, tmpRight);

                Category newParentCategory = db.Categories.Find(parent);
                tmpLeft = newParentCategory.Right;
                tmpRight = newParentCategory.Right + 1;

                UpdateTreeAfterAdd(newParentCategory.Left, newParentCategory.Right);

                categoryToEdit.Left = tmpLeft;
                categoryToEdit.Right = tmpRight;
                db.SaveChanges();
            }
            db.SaveChanges();
        }

        /// <summary>
        /// Update tree structure after removal of the category
        /// </summary>
        /// <param name="left">The left value of the deleting category</param>
        /// <param name="right">The right value of the delteing category</param>
        private static void UpdateTreeAfterDelete(int left, int right)
        {
            PInitiativesEntities db = new PInitiativesEntities();
            var categories = db.Categories.Where(c => c.Right >= right);

            foreach (Category c in categories)
            {
                if (c.Left > left)
                    c.Left -= 2;
                c.Right -= 2;
            }
            db.SaveChanges();
        }

        /// <summary>
        /// Update tree structure after adding category
        /// </summary>
        /// <param name="left">The left value of the parent category</param>
        /// <param name="right">The right value of the parent category</param>
        private static void UpdateTreeAfterAdd(int left, int right)
        {
            PInitiativesEntities db = new PInitiativesEntities();
            var categories = db.Categories.Where(c => c.Right >= right);

            foreach (Category c in categories)
            {
                if (c.Left > left)
                    c.Left += 2;
                c.Right += 2;
            }
            db.SaveChanges();
        }
    }
}